package org.spring.springboot.config.redlock;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 *
 */
@Component
public class RedisLocker implements DistributedLocker {

	private final static String LOCKER_PREFIX = "lock:";

	@Autowired
	RedissonConnector redissonConnector;

	@Override
	public <T> T tryLock(String resourceName, AquiredLockWorker<T> worker)
			throws InterruptedException, UnableToAquireLockException, Exception {

		return tryLock(resourceName, worker, 100);
	}

	@Override
	public <T> T tryLock(String resourceName, AquiredLockWorker<T> worker, int lockTime)
			throws UnableToAquireLockException, Exception {
		RedissonClient redisson = redissonConnector.getClient();
		RLock lock = redisson.getLock(LOCKER_PREFIX + resourceName);
		
		// 尝试加锁，如果被锁了，最多等待2秒，途中锁被解就上锁，到了等待时间就fasle.上锁以后lockTime秒自动解锁
		boolean success = lock.tryLock(2, lockTime, TimeUnit.SECONDS);// 如果锁被占用，同步等待100秒
		if (success) {
			try {
				// 返回是
				// 调用AquiredLockWorker中的方法，因为该方法目前没有写实现，当在调用lock时候就需要重载（实现），那么该覆盖的方案就是我们需要锁的逻辑内容
				return worker.invokeAfterLockAquire();
			} finally {
				lock.unlock();
			}
		}
		throw new UnableToAquireLockException();
	}
	//这个方法是为了定时任务的   在并发时候  多个服务器争一把锁  拿到后运行定时task 运行完不解锁 锁持续100秒 服务器等待锁时间设为0 随后就放弃等待
	@Override
	public <T> T tryLockAndNnlock(String resourceName, AquiredLockWorker<T> worker, int lockTime)
			throws UnableToAquireLockException, Exception {
		RedissonClient redisson = redissonConnector.getClient();
		RLock lock = redisson.getLock(LOCKER_PREFIX + resourceName);
//		System.out.println("锁的是否在:" + lock.isLocked());
		boolean success = false;
//		System.out.println("当前线程是否可以拿到锁:"+success);
		if (success = lock.tryLock(0, lockTime, TimeUnit.SECONDS)) {// 如果锁被占用，同步等待第一个参数秒
			try {
				// 返回是调用AquiredLockWorker中的方法，因为该方法目前没有写实现，当在调用lock时候就需要重载（实现），那么该覆盖的方案就是我们需要锁的逻辑内容
				return worker.invokeAfterLockAquire();
			} finally {
				System.out.println("获取了锁，任务执行");
			}
		}
		System.out.println("当前线程不能获取锁，任务未执行");
		return null;
//		throw new UnableToAquireLockException();
	}

}
